/////////////////////////////////////////////////////////////////////////////
// 2023 -
//open source under Apache License Version 2.0
/////////////////////////////////////////////////////////////////////////////
//  Modifications by Kumo Inc.
// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//




#ifndef _HDFS_LIBHDFS3_CLIENT_FAULTJECTOR_H_
#define _HDFS_LIBHDFS3_CLIENT_FAULTJECTOR_H_

#include <mutex>

namespace Hdfs {

namespace Internal {
class FaultInjector {
public:
    ~FaultInjector() {};
    FaultInjector(const FaultInjector &) = delete;
    FaultInjector & operator=(const FaultInjector &) = delete;

    static FaultInjector & get() {
        static FaultInjector instance;
        return instance;
    }

private:
    FaultInjector() = default;

private:
    int32_t badNodesForRead = 0;
    int64_t writeKillPos = 0;
    int64_t ackKillPos = 0;
    bool testWriteKill = false;
    bool testAckKill = false;
    bool closePipeline = false;
    bool createOutputStreamFailed = false;
    std::mutex mtx;

public:
    void setBadNodesForRead(int32_t val) {
        badNodesForRead = val;
    }

    bool testBadReader() {
        if (badNodesForRead > 0) {
            badNodesForRead--;
            return true;
        }
        return false;
    }

    void setWriteKillPos(int64_t pos) {
        writeKillPos = pos;
        testWriteKill = true;
    }

    bool testBadWriterAtKillPos(int64_t pos) {
        if (testWriteKill && pos >= writeKillPos) {
            testWriteKill = false;
            return true;
        }
        return false;
    }

    void setAckKillPos(int64_t pos) {
        ackKillPos = pos;
        testAckKill = true;
    }

    bool testBadWriterAtAckPos(int64_t pos) {
        std::lock_guard<std::mutex> lock(mtx);
        if (testAckKill && pos >= ackKillPos) {
            testAckKill = false;
            return true;
        }
        return false;
    }

    void setPipelineClose(bool val) {
        closePipeline = val;
    }

    bool testPipelineClose() {
        if (closePipeline) {
            closePipeline = false;
            return true;
        }
        return false;
    }

    void setCreateOutputStreamFailed(bool val) {
        createOutputStreamFailed = val;
    }

    bool testCreateOutputStreamFailed() {
        if (createOutputStreamFailed) {
            createOutputStreamFailed = false;
            return true;
        }
        return false;
    }

};

}
}

#endif /* _HDFS_LIBHDFS3_CLIENT_FAULTJECTOR_H_ */
